import { isObject, isString,isArray } from '../libs/types'
// #ifndef APP
	// #ifdef VUE2
	import initSqlJs from './sql-wasm.js' 
	// #endif
// #endif
class sqlite{
	constructor(conf={}){
		this.config = {
			base:'_doc/',
			path:'data/default.db',
			name:'wyapp',
			...conf
		}
		// #ifndef APP
		
		let {base,path,name}=this.config
		this.dbkey=`${base}-${path}-${name}`
		var that=this
		that.db=null
			// #ifdef VUE2
			initSqlJs().then(function(SQL){
				that.db= new SQL.Database(); 
			})
			// #endif 
		// #endif
	}
	getH5Db(){
		var that=this
		return new Promise((resolve, reject) => {
			if(this.db){
				resolve(this.db)
			}
			else{
				initSqlJs().then(function(SQL){
					that.db= new SQL.Database(); 
					resolve(that.db)
				})
			}
		})	
	}
	async openDB(){
		let option={
			name: this.config.name,
			path: this.config.base+this.config.path
		}
		return new Promise((resolve, reject) => {
			//#ifndef APP
			resolve({ret:true,msg:'h5'})
			//#endif
			plus.sqlite.openDatabase({
				...option,
				success: function(e) {
					resolve({ret:true,msg:JSON.stringify(e)})
				
				},
				fail: function(e) {
					console.log(JSON.stringify(e))
					resolve({ret:false,msg:JSON.stringify(e)})
				}
			});
		})
	}
	isOpenDB(){
		let option={
			name: this.config.name,
			path: this.config.base+this.config.path
		}
		//#ifndef APP
		return true
		//#endif
		let res=plus.sqlite.isOpenDatabase(option)
		return res
	}
	async executeSQL(sql){
		if(isObject(sql)){
			sql=this.filter(sql)
		} 
		const option=this.config
		let isOpen=this.isOpenDB()
		if(!isOpen){
			let {ret,msg}=await this.openDB()
			isOpen=ret
		}
		return new Promise((resolve, reject) => {
			//#ifndef APP
			this.getH5Db().then((db)=>{ 
				var data=db? db.run(sql):null;
				resolve({ret:true,msg:'h5',data})
			})  
			//#endif 
			if(!isOpen){
				reject({ret:false,msg:'db is not open'})
			}else{
				plus.sqlite.executeSql({
					name: option.name,
					sql: sql,
					success: function(e) {
						if (process.env.NODE_ENV === 'development') {
							//console.log('executeSql success--'+sql)
							console.log('executeSql success--')
						}
						resolve({ret:true,msg:'executeSql success'})
					},
					fail: function(e) {
						if (process.env.NODE_ENV === 'development') {
							console.log(JSON.stringify(e))
							console.log('executeSql fail--'+sql)
						}
						resolve({ret:false,msg:JSON.stringify(e)})
					}
				});
			}
		})
	}
	async selectSQL(sql){
		if(isObject(sql)){
			sql=this.filter(sql)
		}
		const option=this.config
		let isOpen=this.isOpenDB()
		if(!isOpen){
			let {ret,msg}=await this.openDB()
			isOpen=ret
		}
		return new Promise((resolve, reject) => {
			//#ifndef APP
			this.getH5Db().then((db)=>{
				var data= db?db.exec(sql):[];
				resolve({ret:true,msg:'h5',data:data})
			}) 
			//#endif
			if(!isOpen){
				reject({ret:false,msg:'db is not open'})
			}else{
				plus.sqlite.selectSql({
					name: option.name,
					sql: sql,
					success: function(e) {
						if (process.env.NODE_ENV === 'development') {
							console.log('selectSql success--'+sql)
						}
						resolve({ret:true,msg:'selectSql success',data:e})
					},
					fail: function(e) {
						if (process.env.NODE_ENV === 'development') {
							console.log(JSON.stringify(e))
							console.log('selectSql fail--'+sql)
						}
						resolve({ret:false,msg:'selectSql fail',data:e})
					}
				}); 
			} 
		})
	}
	async closeDB(){
		return new Promise((resolve, reject) => {
			let res=this.isOpenDB()
			if(res){
				resolve({ret:true,msg:'关闭数据库成功'})
			}else{
				plus.sqlite.closeDatabase({
					name: this.config.name,
					success: function(e) {
						resolve({ret:true,msg:JSON.stringify(e)})
					},
					fail: function(e) {
						resolve({ret:false,msg:JSON.stringify(e)})
					}
				});
			}
		})
		
	}
	
	//根据配置参数生成sql语句
	filter(_option) {
		let option={
			table:'data',
			action:'select',
			field:null,
			where:null,
			page:null,//{p:1,n:10}
			order:null
		}
		option={...option,..._option}
		let {action,field,table,where,values,sql,order,page}=option
		if(sql){
			return sql 
		}
		let vals=[]
		let keys=[]
		switch(action){
			case 'select':
				sql='select {field} from `{table}` ' 
				sql=sql.format({
					table:table,
					field:field?'`'+field+'`':'*'
				})
				break
			 case 'insert':
				sql='insert into `{table}` ({field}) values({values}) ' 
				for(let key in values){
					keys.push('`'+key+'`')
					if(isString(values[key])){
						vals.push('\''+values[key]+'\'')
					}else{
						vals.push(values[key])
					}
				}
				sql=sql.format({
					table:table,
					field:keys.join(','),
					values:vals.join(',')
				})
				break
			case 'update':
				sql='update `{table}` set {values} ' 
				for(let key in values){
					if(isString(values[key])){
						vals.push(key+'=\''+values[key]+'\'')
					}else{
						vals.push(key+'='+values[key])
					}
				}
				sql=sql.format({
					table:table,
					values:vals.join(',')
				})
				break
			case 'counter':
				sql='update `{table}` set {values} '
				for(let key in values){
					let v=values[key]
					let k='`'+key+'`'
					if(v>0){
						v='+'+v
					}
					vals.push(k+'='+k+v)
				}
				sql=sql.format({
					table:table,
					values:vals.join(',')
				})
				break
			case 'count':
				sql='select count({field}) from `{table}` '
				sql=sql.format({
					table:table,
					field:'`'+field+'`'?field:'*'
				})
				break
			
			case 'delete':
				sql='delete from `{table}` ' 
				sql=sql.format({
					table:table
				})
				break
			case 'create':
				sql='create table if not exists `{table}`({values})'
				for(let key in values){
					let model={
						name:'',
						type:'CHAR',
						length:'225'
					}
					model={...model,...values[key]}
					vals.push('`'+model.name+'` '+model.type+'('+model.length+')')
				}
				sql=sql.format({
					table:table,
					values:vals.join(',')
				})
				break
			case 'drop':
				sql='drop table `{table}`'
				sql=sql.format({
					table:table
				})
				break
		}
		if(where){
			let strWhere=where
			if(isObject(where)){
				strWhere='1=1'
				for(let key in where){
					if(!isObject(where[key])){
						if(isString(where[key])){
							strWhere+=' and `'+key+'`=\''+where[key]+'\''
						}
						else{
							strWhere+=' and `'+key+'`='+where[key]+''
						}
					}
					else{
						let {op,sp,v,gp}=where[key]
						let k=key
						sp=sp?sp:'and',
						op=op?op:'='
						let str=''
						switch(op){
							case 'like':
								str='`{k}` {op} \'%{v}%\'' 
								str=str.format({
									op,k,v
								})
								break
							case '=':
							case '>':
							case '>=':
							case '<':
							case '<=':
							case '<>':
								str='`{k}` {op} {v}'
								if(isString(v)){
									v='\''+v+'\''
								}
								str=str.format({
									op,k,v
								})
								break
							case 'in':
								str='`{k}` {op} ({v})'
								if(isArray(v)){
									let vs=[]
									for(let i=0;i<v.length;i++){
										if(isString(v[i])){
											vs.push('\''+v[i]+'\'')
											
										}else{
											vs.push(v[i])
										}
									}
									v=vs.join(',')
								}
								str=str.format({
									op,k,v
								})
								break
						}
						if(gp){
							if(gp=='('){
								str=' '+sp+' '+gp+str
							}else{
								str=' '+sp+' '+str+gp
							}
						}else{
							str=' '+sp+' '+str
						}
						strWhere+=str
					}
				}
			}
			sql+=' where '+strWhere
		}
		if(order){
			let orderStr=order
			if(isObject(order)){
				orderStr=''
				let orders=[]
				for(let key in order){
					orders.push('`'+key+'` '+order[key])
					
				}
				orderStr=orders.join(',')
			}
			sql+=' order by '+orderStr
		}
		if(page){
			sql+=' limit '+(page.p-1)*page.n+','+page.n
		}
		return sql
	}
	async createTable(_option){
		let option={
			action:'create'
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.executeSQL(sql)
	}
	async dropTable(_option){
		let option={
			action:'drop'
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.executeSQL(sql)
	}
	async getList(_option){
		let option={
			action:'select',
			page:{
				p:1,
				n:10
			}
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.selectSQL(sql)
	}
	getModel(_option){
		let option={
			action:'select',
			page:{
				p:1,
				n:1
			}
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.selectSQL(sql)
	}
	insertModel(_option){
		let option={
			action:'insert'
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.executeSQL(sql)
	}
	updateModel(_option){
		let option={
			action:'update'
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.executeSQL(sql)
	}
	deleteModel(_option){
		let option={
			action:'delete'
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.executeSQL(sql)
	}
	getCount(_option){
		let option={
			action:'count'
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.selectSQL(sql)
	}
	updateCounter(){
		let option={
			action:'counter'
		}
		option={...option,..._option}
		let sql=this.filter(option)
		return this.executeSQL(sql)
	}
	/*,
	async dbTest(){
		this.getModel({
			table:this.SingleTableName,
			where:{
				key:'sdad'
			}
		}).then((sql)=>{
			console.log(sql)
		})
		this.insertModel({
			table:this.SingleTableName,
			values:{
				key:'1qaz2wsx',
				data:'https://ask.dcloud.net.cn/article/35232',
				dateline:Date.now()
			}
			 
		}).then((sql)=>{
			console.log(sql)
		})
		this.updateModel({
			table:this.SingleTableName,
			values:{
				data:'https://ask.dcloud.net.cn/article/35232dasd',
				dateline:Date.now()
			},
			where:{
				key:'1qaz2wsx'
			}
			 
		}).then((sql)=>{
			console.log(sql)
		})
		this.deleteModel({
			table:this.SingleTableName,
			where:{
				key:'1qaz2wsx'
			}
			 
		}).then((sql)=>{
			console.log(sql)
		})
		this.getList({
			table:this.SingleTableName,
			where:{
				key:'1qaz2wsx'
			},
			page:{
				p:1,
				n:20
			}
			 
		}).then((sql)=>{
			console.log(sql)
		})
	}*/
}
export default {
	/**
	 * 获取状态机
	 * @param {Array} state 状态列表
	 * @param {Array} trigger 触发器列表
	 * @param {String} 初始状态  
	 */
	getInstance(config={}){
		return new sqlite(config)
	}
};